package moonshine
{
	import __AS3__.vec.Vector;
	
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Rectangle;
	import flash.text.engine.ContentElement;
	import flash.text.engine.ElementFormat;
	import flash.text.engine.GroupElement;
	import flash.text.engine.TabAlignment;
	import flash.text.engine.TabStop;
	import flash.text.engine.TextBlock;
	import flash.text.engine.TextElement;
	import flash.text.engine.TextLine;
	import flash.ui.Mouse;
	import flash.ui.MouseCursor;
	import flash.utils.Timer;
	
	
	public class TextLineRenderer extends Sprite
	{	
		private static var tabStops:Vector.<TabStop> = Vector.<TabStop>([
														new TabStop(TabAlignment.START, 20),
														new TabStop(TabAlignment.START, 40),
														new TabStop(TabAlignment.START, 60),
														new TabStop(TabAlignment.START, 80),
														new TabStop(TabAlignment.START, 100),
														new TabStop(TabAlignment.START, 120),
														new TabStop(TabAlignment.START, 140),
														new TabStop(TabAlignment.START, 160),
														new TabStop(TabAlignment.START, 180),
														new TabStop(TabAlignment.START, 200),
														new TabStop(TabAlignment.START, 220),
														new TabStop(TabAlignment.START, 240),
														new TabStop(TabAlignment.START, 260),
														new TabStop(TabAlignment.START, 280),
														new TabStop(TabAlignment.START, 300),
														new TabStop(TabAlignment.START, 320),
														new TabStop(TabAlignment.START, 340),
														new TabStop(TabAlignment.START, 360),
														new TabStop(TabAlignment.START, 380),
														new TabStop(TabAlignment.START, 400),
														new TabStop(TabAlignment.START, 420),
														new TabStop(TabAlignment.START, 440),
														new TabStop(TabAlignment.START, 460),
														new TabStop(TabAlignment.START, 480)
														]);

		private var textBlock:TextBlock = new TextBlock();
		private var textLine:TextLine;
		
		private var marker:Sprite;
		private var markerBlinkTimer:Timer;
		
		private var selection:Sprite;
		
		
		
		public var dataIndex:int;
		
		private var _data:String;
		public function get data():String 
		{
			return _data;
		}
		public function set data(v:String):void 
		{
			focus = false;
			
			if (textLine)
			{
				removeChild(textLine);
			}
			_data = v;
			
            var format:ElementFormat = new ElementFormat();
            var textElement:TextElement = new TextElement(v, format); 

            var groupElement:GroupElement = new GroupElement();
            var e:Vector.<ContentElement> = new Vector.<ContentElement>();
            e.push(textElement);
            
            groupElement.setElements(e);
   
            textBlock.tabStops = tabStops;
            textBlock.content = groupElement; 
            textLine = textBlock.createTextLine(null, 800);
            
            if (textLine) {
            	textLine.mouseEnabled = false;
            	addChild(textLine);
            	textLine.x = 0;
            	textLine.y = 12;
            }
		}
		
		private var _caretPosition:int;
		public function get caretPosition():int
		{
			return _caretPosition;
		}
		public function set caretPosition(charIndex:int):void
		{
			_caretPosition = charIndex;
			drawCaret(charIndex);
		}
		
		public function insert(s:String, position:int):void
		{
			// TODO: Remove and invalidate line instead
			data = data.substring(0, position) + s + data.substring(position);
			drawCaret(position+s.length);
		}
		
		public function TextLineRenderer()
		{
			super();
			init();
		}
		
		private function init():void 
		{
			selection = new Sprite();
			addChild(selection);
			
			marker = new Sprite();
			addChild(marker);
			
			markerBlinkTimer = new Timer(600);
			markerBlinkTimer.addEventListener(TimerEvent.TIMER, markerBlink);
			
			addEventListener(MouseEvent.MOUSE_OVER, handleMouseOver);
			addEventListener(MouseEvent.MOUSE_OUT, handleMouseOut);
			
			var s:Sprite = new Sprite();
			addChild(s);
			s.graphics.beginFill(0x0, 0);
			s.graphics.drawRect(0, 0, 600, 16);
			s.graphics.endFill();
		}
		
		public function set focus(v:Boolean):void
		{
			if (v)
			{
				markerBlinkTimer.start();
				marker.visible = true;
				
				// Background line fill
				graphics.clear();
				graphics.beginFill(0xFCC1AA);
				graphics.drawRect(0, 0, 2000, 16); 
				graphics.endFill();
			}
			else
			{
				graphics.clear();
				markerBlinkTimer.stop();
				marker.visible = false;	
			}
		}
		
		public function drawCaret(beforeCharAtIndex:int):void
		{
			var bounds:Rectangle;
			
			if (beforeCharAtIndex == 0)
			{
				drawMarkerAtPosition( 0, 0 );
			}
			else if (beforeCharAtIndex >= data.length)
			{
				bounds = textLine.getAtomBounds(data.length-1);
				drawMarkerAtPosition( bounds.x+bounds.width, 0 );
			}
			else
			{
				bounds = textLine.getAtomBounds(beforeCharAtIndex);
				drawMarkerAtPosition( bounds.x, 0 );
			}
		}
		
		public function drawSelection(start:int, end:int):void
		{
			if (start == end || start < 0) 
			{
				removeSelection();
				return;	
			}
			if (start > end)
			{
				var tmp:int = start;
				start = end;
				end = tmp;
			}
		
			var startBox:Rectangle = textLine.getAtomBounds(start);
			var endBox:Rectangle = textLine.getAtomBounds(end-1);
			var selWidth:int = (endBox.x+endBox.width)-startBox.x; 
			
			var g:Graphics = selection.graphics;
			g.clear();
			g.beginFill(0xFF0000);
			g.drawRect(startBox.x, 0, selWidth, 16);
			g.endFill();
		}
		
		public function drawFullLineSelection(lineWidth:int, startAtChar:int=0):void
		{
			var start_x:int = 0;
			if (startAtChar > 0)
			{
				if (startAtChar >= data.length) startAtChar = data.length-1;
				trace("s: " + startAtChar);
				trace("l: " + data.length);
				start_x = textLine.getAtomBounds(startAtChar).x;
			}
			
			var g:Graphics = selection.graphics;
			g.clear();
			g.beginFill(0xFF0000);
			g.drawRect(start_x, 0, lineWidth-start_x, 16);
			g.endFill();
		}
		
		public function removeSelection():void
		{
			selection.graphics.clear();
		}
		
		public function getCharIndexFromPoint(x:int, y:int):int
		{
			var i:int;
			if (x+1 > textLine.width) {
				return data.length;
			} 
			else
			{
				i = textLine.getAtomIndexAtPoint(x, this.y+8);	
			}
			
			if (i == -1) return i;
			var bounds:Rectangle = textLine.getAtomBounds(i);
			var center:int = bounds.x + (bounds.width/2);
			if (x >= center) {
				i++;
			}
			
			return i;
		}
		
		private function drawMarkerAtPosition(x:int, y:int):void
		{
			marker.graphics.clear();
			marker.graphics.beginFill(0x0, 0.5);
			marker.graphics.drawRect(x, 0, 4, 16);
			marker.graphics.endFill();
		}
		
		private function markerBlink(event:TimerEvent):void
		{
			marker.visible = !marker.visible;
		}
		
		private function handleMouseOver(event:MouseEvent):void
		{
			Mouse.cursor = MouseCursor.IBEAM;
		}
		
		private function handleMouseOut(event:MouseEvent):void
		{
			Mouse.cursor = MouseCursor.ARROW;
		}

	}
}